﻿using System;
using System.Collections.Generic;
using System.Xml;
using DocumentBuilder.Components;

namespace DocumentBuilder
{
    public enum DocumentType
    {
        ViewFull,
        ViewLess
    }

    public class Document : IJsonConvertible
    {
        private readonly XmlDocument _xmlDocument = null;

        /// <summary>
        /// Components in Document to load
        /// (Note: Components are loaded in the sequence specified here, which should not be changed)
        /// </summary>
        private static readonly Dictionary<ComponentType, string> XPaths = new Dictionary<ComponentType, string>()
                                                        {
                                                            {ComponentType.Query, "/document/queryset/query"},
                                                            {ComponentType.ViewObject, "/document/objects/object"},
                                                            {ComponentType.View, "/document/view"},
                                                        };

        public String Id { get; private set; }
        public DocumentType DocumentType { get; private set; }
        public View View { get; private set; }
        public Dictionary<String, ViewObject> ViewObjects { get; private set; }
        public Dictionary<String, Query> Queries { get; private set; }
        public DocumentLoadContext LoadContext { get; private set; }
        public Dictionary<String, List<DocumentLoadContext>> DependentDocuments { get; private set; }

        public Document()
        {
            _xmlDocument = new XmlDocument();
            ViewObjects = new Dictionary<string, ViewObject>();
            Queries = new Dictionary<string, Query>();
            DependentDocuments = new Dictionary<string, List<DocumentLoadContext>>();
        }

        /// <summary>
        /// Loads the xml document from filePath
        /// </summary>
        /// <param name="xmlPath"></param>
        public void Load(String xmlPath, DocumentLoadContext loadContext)
        {
            _xmlDocument.Load(xmlPath);
            LoadContext = loadContext;

            foreach (var xPathKey in XPaths.Keys)
            {
                LoadComponent(xPathKey, XPaths[xPathKey]);
            }

            DocumentType = View == null ? DocumentType.ViewLess : DocumentType.ViewFull;
        }

        private void LoadComponent(ComponentType componentType, string xPath)
        {
            switch(componentType)
            {
                case ComponentType.Query:
                    var querySetNodes = _xmlDocument.SelectNodes(xPath);
                    if (querySetNodes != null)
                        foreach (XmlNode queryNode in querySetNodes)
                        {
                            var query = Query.Create(this, queryNode);
                            Queries.Add(query.Id, query);
                        }
                    break;
                case ComponentType.View:
                    View = View.Create(this, _xmlDocument.SelectSingleNode(xPath));
                    break;
                case ComponentType.ViewObject:
                    var viewObjectNodes = _xmlDocument.SelectNodes(xPath);
                    if (viewObjectNodes != null)
                        foreach (XmlNode viewObjectNode in viewObjectNodes)
                        {
                            var viewObject = ViewObject.Create(this, viewObjectNode);
                            ViewObjects.Add(viewObject.Name, viewObject);
                        }
                    break;
            }
        }

        #region IJsonConvertible Members

        public void PaintJsonString(System.Text.StringBuilder jsonCanvas)
        {
            jsonCanvas.Append("{");

            if (DocumentType == DocumentType.ViewFull)
            {
                jsonCanvas.Append("\"view\": ");
                View.PaintJsonString(jsonCanvas);
            }

            if (jsonCanvas.Length > 1
                    && DependentDocuments.Count > 0)
                jsonCanvas.Append(",");

            int cnt = 0;
            foreach (var path in DependentDocuments.Keys)
            {
                if (cnt == 0)
                    jsonCanvas.Append("\"dependentDocuments\": [");

                foreach (var context in DependentDocuments[path])
                {
                    jsonCanvas.Append("{");
                    jsonCanvas.Append(String.Format("\"docPath\": \"{0}\", ", path));
                    context.PaintJsonString(jsonCanvas);
                    jsonCanvas.Append("}");
                }

                if (cnt == DependentDocuments.Count - 1)
                    jsonCanvas.Append("]");
                else
                    jsonCanvas.Append(",");

                cnt++;
            }

            jsonCanvas.Append("}");
        }

        #endregion
    }
}